/*
 * UnitOfWork.java
 *
 * Copyright (c)2007, HeadCase Humanufacturing, Inc. All rights reserved.
 * CONFIDENTIAL AND PROPRIETARY. NOT FOR DISTRIBUTION.
 */
package com.headcaselabs.work;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.headcaselabs.orchestra.JobDaemon;


/**
 * Implements pattern for a callable unit of work.
 *
 * @author Paco Nathan
 * @author Florian Leibert
 */

public abstract class
    UnitOfWork
    implements Callable<Integer>, Monitorable
{
 
		//Fields from "Job"
		protected String id = null;
		protected String messageId = null;
		protected String queueName = null;
  	protected Long	creationTime = null;
  	
  	//UnitOfWork 
    protected boolean can_store = true;
    protected long elapsed_ticks = 0L;
    protected String status_message = null;
    protected Monitorable monitor = null;
    protected boolean finished = false;
    protected long max_time = 0L;
    protected long start_time = 0L;
    protected boolean interrupted = false;
    protected transient Future<?> future;

    private final static Log log_ =
      LogFactory.getLog(UnitOfWork.class.getName());

    /**
     * Computes a result, or throws an exception if unable to do so.
     */

    public abstract Integer
        call ()
        ;


    /**
     * Persists the computed result, if not cancelled.
     */

    public abstract void
        store ()
        ;


    /**
     * Clean up any temporary files.
     */

    public abstract void
        cleanup ()
        ;


    /**
     * Set the "can store" flag.
     */

    public void
	setCanStore (final boolean can_store)
    {
	this.can_store = can_store;
    }


    /**
     * Access the "can store" flag.
     */

    public boolean
	getCanStore ()
    {
	return can_store;
    }
    
    
    public long getStartTime() {
        return start_time;
    }


    /**
     * @return the max_time.
     */
    public long getMax_time() {
        return max_time;
    }


    /**
     * @param max_time The max_time to set.
     */
    public void setMax_time(long max_time) {
        this.max_time = max_time;
    }
    
    
    public synchronized void postProcess() {
	    	log_.debug("Entered Post Processing stage for task with"+id);
	  		long t0 = System.currentTimeMillis();
	    	finished = true;
	      this.elapsed_ticks = System.currentTimeMillis() - start_time;
	      monitor.cancel();
				log_.debug("About to delete job...");
	      JobDaemon.getInstance().getSQSUtils().deleteJob(getMessageId(),getId(),getQueueName());
				log_.debug("Updating job time in the queues.");
	    	JobDaemon.getInstance().getSQSUtils().updateJobTime(this.id, this.elapsed_ticks);
				setFuture(null);
				log_.debug("Removed job parameter mappings...");
	    	long t1 = System.currentTimeMillis();
	    	
	    	log_.debug("Blocked execution during postProcess() for: "+(t1-t0)+"ms");
	    	log_.debug("Leaving Post Processing stage for task with"+id);

    }
    
    public synchronized void cancel() {
    		log_.debug("Trying to cancel task with id:"+id);
    		long t0 = System.currentTimeMillis();
    		log_.info("---> Cancelled UnitOfWork with id:"+id);
        finished = false;   
        interrupted = true;
        //Future<?> me = JobUtils.getFuture(this);
        log_.debug("Trying to cancel future for this task with id:"+id);
        //me.cancel(true);
        getFuture().cancel(true);
        log_.debug("Cancelled future for this task with id:"+id+ " ... trying to remove it");
       // JobUtils.removeFuture(null);
        setFuture(null);

        log_.debug("Set future for this task to null");
      	long t1 = System.currentTimeMillis();
      	log_.info("Blocked execution during cancel() for: "+(t1-t0)+"ms");
    		log_.debug("Cancelled task with id:"+id);
    		log_.debug("Trying to add current task to list of unfinished tasks");
    		//TODO:JobUtils.addCancelledJob(getId());
    		JobDaemon.getInstance().getSQSUtils().markJobCancelled(getId(), getQueueName());
	      JobDaemon.getInstance().getSQSUtils().deleteJob(getMessageId(),getId(),getQueueName());
    		log_.debug("Added current task to list of unfinished tasks");
    	
    }
    
    public synchronized boolean getIsFinished() {
        return finished;
    }
    public synchronized boolean getWasInterrupted() {
        return interrupted;
    }
    
    public synchronized void registerSupervisee(Monitorable supervisee) {
        this.monitor = supervisee;
    }
    
    /**
     * @return id
     */
    public synchronized String getId() {
        return id;
    }
    /**
     * Sets the id for this UnitOfWork
     * @param id
     */
    public void setId(String id) {
    	this.id = id;
    }


		/**
		 * @return the elapsed_ticks
		 */
		public synchronized long getElapsed_ticks() {
			return elapsed_ticks;
		}
		
		public Future<?> getFuture() {
			return future;
		}

		public void setFuture(Future<?> future) {
			this.future = future;
		}

		/**
		 * @return the messageId
		 */
		public synchronized String getMessageId() {
			return messageId;
		}


		/**
		 * @param messageId the messageId to set
		 */
		public void setMessageId(String messageId) {
			this.messageId = messageId;
		}


		/**
		 * @return the queueName
		 */
		public synchronized String getQueueName() {
			return queueName;
		}


		/**
		 * @param queueName the queueName to set
		 */
		public void setQueueName(String queueName) {
			this.queueName = queueName;
		}


		/**
		 * @return the creationTime
		 */
		public Long getCreationTime() {
			return creationTime;
		}


		/**
		 * @param creationTime the creationTime to set
		 */
		public void setCreationTime(Long creationTime) {
			this.creationTime = creationTime;
		}


		/**
		 * @generated by CodeSugar http://sourceforge.net/projects/codesugar */
		
		public String toString() {
			StringBuffer buffer = new StringBuffer();
			buffer.append("[UnitOfWork:");
			buffer.append(" id: ");
			buffer.append(id);
			buffer.append(" messageId: ");
			buffer.append(messageId);
			buffer.append(" queueName: ");
			buffer.append(queueName);
			buffer.append(" can_store: ");
			buffer.append(can_store);
			buffer.append(" elapsed_ticks: ");
			buffer.append(elapsed_ticks);
			buffer.append(" status_message: ");
			buffer.append(status_message);
			buffer.append(" monitor: ");
			buffer.append(monitor);
			buffer.append(" finished: ");
			buffer.append(finished);
			buffer.append(" max_time: ");
			buffer.append(max_time);
			buffer.append(" start_time: ");
			buffer.append(start_time);
			buffer.append(" interrupted: ");
			buffer.append(interrupted);
			buffer.append(" creationTime: ");
			buffer.append(creationTime);
			buffer.append(" future: ");
			buffer.append(future);
			buffer.append("]");
			return buffer.toString();
		}
    
    
}
